package br.com.gr.jcash.dao;

import br.com.gr.jcash.dmp.Conta;
import br.com.gr.jcash.dmp.Movimento;
import br.com.gr.jcash.dmp.TipoCategoria;
import br.com.gr.jcash.dmp.Usuario;
import br.com.gr.jcash.exception.JCashException;
import br.com.gr.jcash.utils.Filtro;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class MovimentoDAO extends AbstractDAO<Movimento, Long> {

    @PersistenceContext(unitName = "jcash-PU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public MovimentoDAO() {
        super(Movimento.class);
    }

    @Override
    public List<Movimento> buscarTodos(Usuario usuario) throws JCashException {
        return buscarTodos("Movimento.buscarTodos", usuario);
    }

    @Override
    public List<Movimento> buscarPorFaixa(Usuario usuario, int[] faixa) throws JCashException {
        return buscarPorFaixa("Movimento.buscarTodos", faixa, usuario);
    }

    @Override
    public Long count(Usuario usuario) throws JCashException {
        return count("Movimento.count", usuario);
    }

    public List<Movimento> buscarTodosFiltro(Usuario usuario, Filtro filtro) throws JCashException {
        Query query;
        try {
            query = gerarQuery(usuario, filtro);
            return query.getResultList();
        } catch (Exception ex) {
            throw new JCashException(ex);
        }
    }

    private Query gerarQuery(Usuario usuario, Filtro filtro) throws Exception {
        HashMap<String, Object> parametros = new HashMap<>();


        StringBuilder sb = new StringBuilder();
        sb.append("select distinct m from Movimento m ");
        sb.append("where m.usuario = :usuario ");
        parametros.put("usuario", usuario);
        sb.append("and m.mvtData between :dataInicial and :dataFinal ");
        parametros.put("dataInicial", filtro.getDataInicial());
        parametros.put("dataFinal", filtro.getDataFinal());

        if (null != filtro.getTipoCategoria()) {
            if (filtro.getTipoCategoria().equals(TipoCategoria.D)) {
                sb.append("and m.ctaDestino.categoria.catTipo = :tipoDestino ");
                parametros.put("tipoDestino", filtro.getTipoCategoria());
            }
            if (filtro.getTipoCategoria().equals(TipoCategoria.R)) {
                sb.append("and m.ctaOrigem.categoria.catTipo = :tipoOrigem ");
                parametros.put("tipoOrigem", filtro.getTipoCategoria());
            }
        }

        if (null != filtro.getCategoria()) {
            if (filtro.getCategoria().getCatTipo().equals(TipoCategoria.D)) {
                sb.append("and m.ctaDestino.categoria = :catDestino ");
                parametros.put("catDestino", filtro.getCategoria());
            }
            
            if (filtro.getCategoria().getCatTipo().equals(TipoCategoria.R)) {
                sb.append("and m.ctaOrigem.categoria = :catOrigem ");
                parametros.put("catOrigem", filtro.getCategoria());
            }
        }

        if (null != filtro.getConta()) {
            sb.append("and (m.ctaOrigem = :origem ");
            sb.append("or m.ctaDestino = :destino) ");
            parametros.put("origem", filtro.getConta());
            parametros.put("destino", filtro.getConta());
        }

        sb.append("order by mvtData ");

        Query query = getEntityManager().createQuery(sb.toString());

        for (Map.Entry<String, Object> entry : parametros.entrySet()) {
            String string = entry.getKey();
            Object object = entry.getValue();
            query.setParameter(string, object);
        }

        return query;

    }

    public Long countPorConta(Usuario usuario, Conta conta) throws JCashException {
        return count("Movimento.countPorConta", usuario, conta, conta);
    }

    public Long countPorContaDataAnterior(Usuario usuario, Conta conta, Date data) throws JCashException {
        return count("Movimento.countPorContaDataAnterior", usuario, conta, conta, data);
    }
}
